home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
dfue
/
elcheapofax
/
faxcmd
/
libfax
/
rcs
/
send.c,v
< prev
next >
Wrap
Text File
|
1995-03-09
|
14KB
|
614 lines
head 1.6;
access;
symbols
OCT93:1.6;
locks;
comment @ * @;
1.6
date 93.10.25.02.20.15; author Rhialto; state Exp;
branches;
next 1.5;
1.5
date 93.09.18.20.23.52; author Rhialto; state Exp;
branches;
next 1.4;
1.4
date 93.09.18.20.16.23; author Rhialto; state Exp;
branches;
next 1.3;
1.3
date 93.07.13.05.41.27; author Rhialto; state Exp;
branches;
next 1.2;
1.2
date 93.06.11.16.15.25; author Rhialto; state Exp;
branches;
next 1.1;
1.1
date 93.06.11.15.19.27; author Rhialto; state Exp;
branches;
next ;
desc
@Initiate, send data, terminate
@
1.6
log
@Make +FBOR flexible.
@
text
@/* $Id: send.c,v 1.5 1993/09/18 20:23:52 Rhialto Exp $
* $Log: send.c,v $
* Revision 1.5 1993/09/18 20:23:52 Rhialto
* Break out faxmodem_sync() from faxmodem_initiate_call(), so you
* must call it after faxmodem_open(). This allows additional commands
* before dialing.
*
* Revision 1.4 1993/09/18 20:16:23 Rhialto
* Add (compile time) choice for +FBOR= value.
*
* Revision 1.3 1993/07/13 05:41:27 Rhialto
* Support for modems that are already fax-connected when we startup.
*
* Revision 1.2 1993/06/11 16:15:25 Rhialto
* First real RCS checkin
*
*/
/*
* This file is part of El Cheapo Fax. All modifications relative to the
* base source are (C) Copyright 1993 by Olaf 'Rhialto' Seibert.
* All rights reserved. The GNU General Public License applies.
*/
/*
This file is part of the NetFax system.
(c) Copyright 1989 by David M. Siegel and Sundar Narasimhan.
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include "log.h"
#include "c2proto.h"
#include "response.h"
#include "swap.h"
#include "read.h"
#include "write.h"
#include "tty.h"
#include "send.h"
#include "gen.h"
/*
Maximum amount of data to send to the modem in one write call:
*/
#define SEND_CHUNK 1024
static int dial(FaxModem * f, char * phonenum);
static int start_xmit(FaxModem * f, int df, int vr, int wd, int ln);
static int end_page(FaxModem * f);
static int end_xmit(FaxModem * f);
static int process_send_response(FaxModem * f);
static int send_page(FaxModem * f, int fd, int last_page);
int read(int, char *, int);
int lseek(int, long, int);
/*
* Dial a number: ATDT
*
* Return codes:
* 0 ok, number has been dialed.
* -1 dial failed.
*/
static int dial(f, phonenum)
FaxModem *f;
char *phonenum;
{
log(L_NOTICE, "dialing: %s", phonenum);
if (FAX_ISSET(f,FAX_F_CONNECT))
return 0;
init_modem_response(f);
if (fdprintf(f->fd, "ATDT%s\r", phonenum) < 0)
return (-1);
if (get_modem_response(f, TIMEOUT_CONNECT) < 0)
return (-1);
/*
* Save away the last numeric result as the result of this
* dial operation. This makes it handy to check what
* happened on the last dial.
*/
f->dialer_code = f->result;
return (0);
}
/*
* Dial to a remote fax machine. (Modem must have been sync'ed first)
*
* Return codes:
* 0 connection to remote modem has been established.
* -1 connection failed.
*/
int faxmodem_initiate_call(f, dialstring)
FaxModem *f;
char *dialstring;
{
/*
* Set phase C data bit order.
*
* The interfax firmware has a bug with received data in
* bitreverse=1 mode, so I will leave it in bor=0, and fudge the
* data in software. (This is not necessarily true anymore)
*/
if (faxmodem_bit_reverse(f, bor_value) < 0) {
log(L_NOTICE, "setting modem to bit reverse=%d failed", bor_value);
return (-1);
}
/*
* Initiate the call to the remote modem.
*/
if (dial(f, dialstring) < 0) {
log(L_NOTICE, "dial failed");
return (-1);
}
return (0);
}
/*
* Begin or continue sending: +FDT
*
* Send the appropriate commands to the fax modem to start transmission
* of a page. After sending the start commands, the modem will respond
* with a message that ends with CONNECT. For now, we don't parse any
* of this message, we just look for the CONNECT. In addition, the
* modem will signal to us that we should start sending G3 data by
* issuing an XON. Thus, we force an XOFF. THe subsequent writes
* to the modem will not start to drain until the XON occurs. Note
* that this part of the protocol may change, according to the most
* recent documention.
*
* Set desired transmission params with +FDT=DF,VR,WD,LN
* DF = Data Format : 0 [1-d huffman]
* VR = Vertical Res : 1 [196 dpi (fine)]
* WD = width : 0 [ 1728 pixels]
* LN = page length : 2 [ Unlimited ]
*
* Return codes:
* 0 ok, proceed with sending data
* -1 setup failed, not ready to send.
*/
static int start_xmit(f, df, vr, wd, ln)
FaxModem *f;
int df, vr, wd, ln;
{
log(L_NOTICE, "setting xmit params: df %d vr %d wd %d ln %d", df, vr, wd, ln);
if (fdprintf(f->fd, "AT+FDT=%d,%d,%d,%d\r", df, vr, wd, ln) < 0)
return (-1);
/*
* Wait for the output to the modem to complete, and then stop
* all further output (via an XOFF). The modem will eventually
* respond with an XON, allowing the data transmission to begin.
*/
tcdrain(f->fd);
ioctl(f->fd, TCXONC, TCOOFF);
/*
* Make sure that we get the CONNECT message from the modem.
*/
return (get_modem_response(f, TIMEOUT_FDT));
}
/*
* end of page, another page from same document is coming: +FET=0
*
* This transmit page punctuation command is issued after a +FDT has
* been issued, and indicates that the current page has completed,
* and another page from the same document is about to be sent.
*
* Return codes:
* 0 all ok
* -1 modem response error
*/
static int end_page(f)
FaxModem *f;
{
log(L_NOTICE, "end of current page, another page will be sent");
if (fdprintf(f->fd, "AT+FET=0\r") < 0)
return (-1);
return (get_modem_response(f, TIMEOUT_END_PAGE));
}
/*
* End of page and end of document: +FET=2
*
* This transmit page punctuation command is issued after a +FDT has
* been issued, and incates that the current page has completed,
* and the document is complete as well.
*
* Return codes:
* 0 all ok
* -1 modem response error
*/
static int end_xmit(f)
FaxModem *f;
{
log(L_NOTICE, "end of current page, document is now complete");
if (fdprintf(f->fd, "AT+FET=2\r") < 0)
return (-1);
return (get_modem_response(f, TIMEOUT_END_XMIT));
}
/*
* When sending data, it is possible to get a CAN message from
* the remote fax. This message indicates that the send should
* be aborted. The DLE ETX sequence should be sent to the DCE
* to ack the abort.
*
* Return codes:
* 0 all ok, proceed with sending
* -1 send failed, check modem flags for more details
*/
static int process_send_response(f)
FaxModem *f;
{
char resp[128];
int resp_len;
int i;
/*
* We poll the fd for any input. If none is available, all
* is fine. If we get any input at all, it should be a CAN
* command, as that is all that the protocol allows. However,
* to be safe we toss out any other junk that may come in.
*/
switch (resp_len = pread(f->fd, resp, sizeof(resp))) {
case -1:
log(L_ERR, "send_page: poll failed: %m");
f->status = MODEM_STATUS_FAILED;
return (-1);
case 0:
return (0);
default:
log(L_INFO, "process_send_response: got \"%.*s\"", resp_len, resp);
for (i = 0; i < resp_len; i++) {
if ((resp[i] & 0x7f) == CAN) {
log(L_NOTICE, "remote fax has canceled transmission");
fdprintf(f->fd, "%c%c", DLE, ETX);
f->flags |= FAX_F_CANCELED;
return (-1);
}
}
return (0);
}
}
/*
* Actually send a page. We assume that we have dialed and connected
* to the remote fax machine, and that all is ready for starting
* the actually transmission.
*
* Return codes:
* 0 page has been succesfully sent
* -1 send of page failed.
* XXX Should support files with more than 1 page
*/
static int send_page(f, fd, last_page)
FaxModem *f;
int fd;
int last_page;
{
log(L_INFO, "sending g3 file");
/*
* Setup things for transmission.
*/
if (start_xmit(f, DF_1DHUFFMAN, VR_FINE, WD_1728, LN_UNLIMITED) < 0)
return (-1);
/*
* Allow modem to send ^S to us. Don't use flow control in the
* other direction, since we need to pass 8 bits.
*/
tty_fc(f->fd, FC_OUTPUT_ON);
/*
* Now send the page.
*/
for (;;) {
unsigned char buf[SEND_CHUNK];
unsigned char buf_copy[SEND_CHUNK*2];
int nchars, ochars;
int i;
/*
* Read in a hunk of data.
*/
if ((nchars = read(fd, buf, sizeof(buf))) < 0) {
log(L_ERR, "send_page: read failed: %m");
tty_fc(f->fd, FC_BOTH_ON);
return (-1);
}
if (nchars == 0)
break;
/*
* Reverse and stuff buffer characters:
*/
ochars = 0;
for (i = 0; i < nchars; i++) {
buf_copy[ochars] = swap_bits(buf[i]);
if (buf_copy[ochars++] == DLE)
buf_copy[ochars++] = DLE;
}
/*
* Write out the buffer to the modem.
*/
if (nwrite(f->fd, (char *)buf_copy, ochars) != ochars) {
log(L_ERR, "send_page: write to modem failed: %m");
tty_fc(f->fd, FC_BOTH_ON);
return (-1);
}
/*
* Check for any response from the modem.
*/
if (process_send_response(f) < 0) {
tty_fc(f->fd, FC_BOTH_ON);
return (-1);
}
}
fdprintf(f->fd, "%c%c", DLE, ETX);
tty_fc(f->fd, FC_BOTH_ON);
if (get_modem_response(f, TIMEOUT_SEND_PAGE) < 0) {
log(L_NOTICE, "an error sending the file has occured");
return (-1);
} else
log(L_INFO, "send of file has completed");
if (last_page)
return (end_xmit(f));
else
return (end_page(f));
}
/*
* Send off a page. If a retransmit is requested, try up to tries number
* of times. If this is the last page of the transmission, set last_page
* to be true. The G3 file to send is opened on the given fd.
*
* Return codes:
* 0 the page was successfully sent
* -1 the send failed, see the modem flags for more details
*/
int faxmodem_send_page(f, fd, last_page, tries)
FaxModem *f;
int fd;
int last_page;
int tries;
{
int i;
long seekpos;
seekpos = lseek(fd, 0, 1); /* Rhialto */
for (i = 0; i < tries; i++) {
if (send_page(f, fd, last_page) < 0)
return (-1);
/*
* If hangup was detected and not last page, then return
* with an error condition.
*/
if (last_page) {
if (FAX_ISSET(f, FAX_F_FHNG) && (f->hangup_code != 0)) {
log(L_NOTICE, "hangup on last page: %d", f->hangup_code);
return (-1);
}
} else {
if (FAX_ISSET(f, FAX_F_FHNG)) {
log(L_NOTICE, "hangup code received while sending pages");
return (-1);
}
}
/*
* Make sure we got a post page response.
*/
if (!FAX_ISSET(f, FAX_F_FPTS)) {
log(L_NOTICE, "didn't receive post page response");
return (-1);
}
switch (f->ppr_code) {
case PPR_MCF:
/* page good */
return (0);
case PPR_RTN:
case PPR_RTP:
/* retrans requested for both these cases */
break;
case PPR_PIN:
case PPR_PIP:
/* interrupt requested, what do we do here? assume failure */
return (-1);
default:
log(L_ERR, "unknown ppr code received");
return (-1);
}
lseek(fd, seekpos, 0); /* Rhialto */
}
f->flags |= FAX_F_RETRIES;
log(L_NOTICE, "failed to successfully send page");
return (-1);
}
#ifdef DEBUG
FaxModem fm;
int send_test(phone)
char *phone;
{
int fd;
log_set_level(LOG_INFO);
if (faxmodem_open(&fm, "/dev/ttyb") < 0) {
fprintf(stderr, "open failed\n");
return (-1);
}
if (faxmodem_initiate_call(&fm, phone) < 0 || !FAX_CONNECTED(&fm)) {
fprintf(stderr, "connection failed\n");
return (-1);
}
if ((fd = open("test.g3.0", O_RDONLY)) < 0) {
fprintf(stderr, "can't open test file\n");
faxmodem_close(&fm);
return (-1);
}
if (faxmodem_send_page(&fm, fd, TRUE, 3) < 0)
fprintf(stderr, "send failed\n");
else
fprintf(stderr, "send was successful\n");
faxmodem_hangup(&fm);
faxmodem_close(&fm);
return (0);
}
#endif
@
1.5
log
@Break out faxmodem_sync() from faxmodem_initiate_call(), so you
must call it after faxmodem_open(). This allows additional commands
before dialing.
@
text
@d1 1
a1 1
/* $Id: send.c,v 1.4 1993/09/18 20:16:23 Rhialto Exp $
d3 5
a67 3
#if BOR_VALUE == BOR_C_REV
#define swap_bits(x) (x)
#endif
d121 2
a122 2
if (faxmodem_bit_reverse(f, BOR_VALUE) < 0) {
log(L_NOTICE, "setting modem to bit reverse=%d failed", BOR_VALUE);
d179 1
a179 1
return (get_modem_response(f, 120));
@
1.4
log
@Add (compile time) choice for +FBOR= value.
@
text
@d1 1
a1 1
/* $Id: send.c,v 1.3 1993/07/13 05:41:27 Rhialto Exp $
d3 3
d102 1
a102 1
* Sync and dial to a remote fax machine.
a111 3
if (faxmodem_sync(f, 10) < 0)
return (-1);
@
1.3
log
@Support for modems that are already fax-connected when we startup.
@
text
@d1 1
a1 1
/* $Id: send.c,v 1.2 1993/06/11 16:15:25 Rhialto Exp $
d3 3
d60 3
d117 1
a117 1
* data in software.
d119 2
a120 2
if (faxmodem_bit_reverse(f, 0) < 0) {
log(L_NOTICE, "setting modem to bit reverse failed");
@
1.2
log
@First real RCS checkin
@
text
@d1 5
a5 2
/* $Id$
* $Log$
d70 3
@
1.1
log
@Initial revision
@
text
@d1 3
@